import java.util.List;
import java.util.Iterator;
import java.util.Properties;

import aima.core.agent.Action;
import aima.core.search.uninformed.UniformCostSearch;
import aima.core.search.framework.GraphSearch;
import aima.core.search.framework.SearchAgent;
import aima.core.search.informed.GreedyBestFirstSearch;
import aima.core.search.framework.Problem;
import aima.core.search.framework.Search;
import aima.core.search.uninformed.BreadthFirstSearch;
import aima.core.search.framework.TreeSearch;
import aima.core.search.informed.AStarSearch;
import aima.core.search.uninformed.DepthLimitedSearch;
import aima.core.search.uninformed.IterativeDeepeningSearch;

/**
 * Demo de varias busquedas no informadas e informadas del problema de los canibales
 */
public class MisionerosDemo {
	
	public static void main(String [] args) {
		MisionerosBFSDemo();
		MisionerosUCSDemo();
		MisionerosDLSDemo();
		MisionerosILSDemo();
		MisionerosAStarTree();
		MisionerosAStarGraph();	
		MisionerosGreedyGraph();
		MisionerosGreedyTree();
	}
	
	private static void MisionerosBFSDemo() {
		System.out.println("Misioneros BFS -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new BreadthFirstSearch();
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosUCSDemo() {
		System.out.println("\nMisioneros UCS -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new UniformCostSearch();
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosDLSDemo() {
		System.out.println("\nMisioneros DLS -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new DepthLimitedSearch(9);
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosILSDemo() {
		System.out.println("\nMisioneros ILS -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new IterativeDeepeningSearch();
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosAStarTree() {
		System.out.println("\nMisioneros AStar Tree Search-->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new AStarSearch(new TreeSearch(),new Heuristica());
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosAStarGraph() {
		System.out.println("\nMisioneros AStar Graph Search -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new AStarSearch(new GraphSearch(), new Heuristica());
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosGreedyGraph() {
		System.out.println("\nMisioneros Greedy Graph Search -->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new GreedyBestFirstSearch(new GraphSearch(), new Heuristica());
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void MisionerosGreedyTree() {
		System.out.println("\nMisioneros Greedy Tree Search-->");
		try {
			Problem problem = new Problem(new EstadoMisioneros(), MisionerosFunctionFactory.getActionsFunction(),
					MisionerosFunctionFactory.getResultFunction(), new MisionerosGoalTest());
			Search search = new GreedyBestFirstSearch(new TreeSearch(), new Heuristica());
			SearchAgent agent = new SearchAgent(problem, search);
			printActions(agent.getActions());
			printInstrumentation(agent.getInstrumentation());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// Sacado del problema del 8 puzzle
	private static void printInstrumentation(Properties properties) {
		Iterator<Object> keys = properties.keySet().iterator();
		while (keys.hasNext()) {
			String key = (String) keys.next();
			String property = properties.getProperty(key);
			System.out.println(key + " : " + property);
		}

	}
	
	// Sacado del problema del 8 puzzle
	private static void printActions(List<Action> actions) {
		for (int i = 0; i < actions.size(); i++) {
			String action = actions.get(i).toString();
			System.out.println(action);
		}
	}
	

}
